use std::borrow::BorrowMut;
use mysql::{Pool, Result, PooledConn};
use mysql::prelude::{Queryable};
use serde::{Deserialize, Serialize};

#[derive(Debug, PartialEq, Eq, Clone)]
pub struct TableField {
    pub field_name: String,
    pub field_type: String,
    pub field_comment: Option<String>,
    pub field_key: String
}

#[derive(Debug, PartialEq, Eq, Clone)]
pub struct TableName {
    pub table_name: String,
    pub table_comment: Option<String>,
    pub table_fields: Vec<TableField>,
}


// 数据库配置
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct DatabaseConfig {
    // 数据库地址
    pub address: String,
    // 端口
    pub port: i32,
    // 用户名
    pub username: String,
    // 密码
    pub password: String,
    // 数据库
    pub database: String,
    // 是否全部转换
    pub is_all: bool,
    // 需要转换的数据表
    pub table_name: Vec<String>,
    // 前缀
    pub table_prefix: String
}

impl DatabaseConfig {

    fn get_table_all(&self, conn: &mut PooledConn) -> Vec<TableName> {
        let sql = if self.is_all {
            format!("select a.table_name, a.table_comment from information_schema.`tables` a where a.table_schema = '{}' and locate('{}', a.table_name)", self.database, self.table_prefix)
        } else {
            let x: Vec<String> = self.table_name.clone().into_iter().map(|item| format!("'{}'", item)).collect();
            format!("select a.table_name, a.table_comment from information_schema.`tables` a where a.table_schema = '{}' and a.table_name in ({})", self.database, x.join(","))
        };

        let result = conn.query_map(sql, |(table_name, table_comment)| {

            TableName {
                table_name,
                table_comment,
                table_fields: Vec::new(),
            }
        });
        if let Ok(data) = result {
            data
        } else {
            vec![]
        }
    }

    fn table_fields(&self, table_name: &mut TableName, conn: &mut PooledConn) {
        let sql = format!("select a.column_name as field_name,a.data_type as field_type,a.column_comment as field_comment,a.column_key as field_key from information_schema.columns a where a.table_name = '{}' and a.table_schema = 'cwz' order by a.ordinal_position asc", table_name.table_name);

        let result = conn.query_map(sql, |(field_name, field_type, field_comment, field_key)| {
            TableField {
                field_name,
                field_type,
                field_comment,
                field_key
            }
        });
        if let Ok(data) = result {
            table_name.table_fields = data;
        }
    }

    pub fn load_fields(&self) -> Result<Vec<TableName>> {
        let link = format!("mysql://{}:{}@{}:{}/{}",
                           self.username,
                           self.password,
                           self.address,
                           self.port,
                           self.database
        );

        let pool = Pool::new(link.as_ref())?;
        let mut conn = pool.get_conn()?;
        let mut tables = self.get_table_all(conn.borrow_mut());
        for table in tables.iter_mut() {
            self.table_fields(table, conn.borrow_mut());
        }
        Ok(tables)
    }


}

#[cfg(test)]
mod tests {

    #[test]
    fn test() {}
}